<?php defined('SYSPATH') or die('No direct script access.');
/**
 * 密码 HASH 处理
 *
 * @author  Yellow.Chow <aultoale@gmail.com>
 * @version $Id: password.php 71 2012-03-16 02:03:52Z yellow.chow $
 * @license http://www.gnu.org/licenses/gpl-3.0.html    GPL 3
 */
class Password
{

    /**
     * 密码哈希盐模
     *
     * @var array
     */
    protected static $_salt_pattern = array('1', '3', '5', '9', '14', '15', '20', '21', '28', '30');

    /**
     * 密码哈希加密方法
     *
     * @var string
     */
    protected static $_hash_method = 'sha1';

    /**
     * 比较密码是否一致
     *
     * @param  string  $hash_password
     * @param  string  $password
     */
    public static function match($hash_password, $password)
    {
        $salt = Password::find_salt($hash_password);

        return (Password::create($password, $salt) === $hash_password);
    }

    /**
     * Creates a hashed password from a plaintext password, inserting salt
     * based on the configured salt pattern.
     *
     * @param  string  $password
     * @param  bool    $salt
     * @return string
     */
    public static function create($password, $salt = FALSE)
    {
        if ($salt === FALSE)
        {
            // Create a salt seed, same length as the number of offsets in the pattern
            $salt = substr(hash('sha1', uniqid(NULL, TRUE)), 0, count(Password::$_salt_pattern));
        }

        // Password hash that the salt will be inserted into
        $hash = Password::hash($salt.$password);

        // Change salt to an array
        $salt = str_split($salt, 1);

        // Returned password
        $password = '';

        // Used to calculate the length of splits
        $last_offset = 0;

        foreach (Password::$_salt_pattern as $offset)
        {
            // Split a new part of the hash off
            $part = substr($hash, 0, $offset - $last_offset);

            // Cut the current part out of the hash
            $hash = substr($hash, $offset - $last_offset);

            // Add the part to the password, appending the salt character
            $password .= $part.array_shift($salt);

            // Set the last offset to the current offset
            $last_offset = $offset;
        }

        // Return the password, with the remaining hash appended
        return $password.$hash;
    }

    /**
     * Perform a hash, using the configured method.
     *
     * @param   string  $str
     * @return  string
     */
    public static function hash($str)
    {
        return hash(Password::$_hash_method, $str);
    }

    /**
     * Finds the salt from a password, based on the configured salt pattern.
     *
     * @param   string  $password
     * @return  string
     */
    public static function find_salt($password)
    {
        $salt = '';

        foreach (Password::$_salt_pattern as $i => $offset)
        {
            // Find salt characters, take a good long look...
            $salt .= substr($password, $offset + $i, 1);
        }

        return $salt;
    }

}